Skip to content

feat(lint): dashboard and report advisories carry a localized user sentence - #33118

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-4p4z2c
Nov 13, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-4p4z2c

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #32837

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

Layer 1 of #32654 for the dashboard and report advisories, in the pattern #32655 landed (validate-security-posture.user-text.ts, finding-user-text.test.ts), under ruling record 6819749037 (option C).

Re-measured first. The card's table (11 ids, a static-scan upper bound) was checked by running every warning push site of the three files whole-stack and through runRuntimeAuthoringRules on main 2c98485d. Nine ids reach the publish door; two do not:

Rule file Door-reaching advisory ids Not reaching the door
validate-widget-bindings.ts (dashboard write) widget-legacy-analytics-shape, dashboard-filter-field-unprovisioned, chart-field-unknown (x-axis site, and the y-axis/series site), chart-measures-missing, widget-measures-missing, chart-dimensions-missing, table-count-only measure-aggregate-incoherent
validate-chart-bindings.ts (report write, a report chart's series[] entry) chart-measure-unknown, chart-axis-not-selected —
validate-page-visualization-bindings.ts — page/visualization-without-binding

The seat agreed to cover the nine only (thread record, 14:18Z). See Acceptance notes for why the two stay on the English message.

packages/lint.

  • validate-widget-bindings.user-text.ts (new, beside the rule): the 7 widget ids' sentences in all 11 PLATFORM_LOCALE_TAGS, in the dashboard editor's terms from ui/packages/i18n (dashboard, widget, dataset, dimensions, values, measure, metric). chart-field-unknown has one arm per position (axis: x, y, series) and widget-measures-missing one per what the widget fails to show (shows: number for the metric family, table for the tabular one), as the rule's message does.
  • validate-chart-bindings.user-text.ts (new): the 2 chart ids' sentences, addressed to the report's chart series entry, the one advisory position the door reaches. chart-axis-not-selected names the measure the chart plots.
  • Push sites: validate-widget-bindings.ts sets userTextParams at the 8 push sites of the 7 ids (both chart-field-unknown sites); validate-chart-bindings.ts sets it on the two ids' report-series findings only, carrying the report name on the report chart binding (ChartBinding.report). Both finding interfaces gain userTextParams?. A query-position chart-measure-unknown (an error) and the page-chart presentation positions (judged on pages, which no per-write snapshot carries) carry none. Rule ids, message and hint are unchanged.
  • finding-user-text.ts: FINDING_USER_TEXT_CATALOG merges the two catalogs beside the security one via mergeUserTextCatalogs.
  • No new export: the catalogs stay internal, as SECURITY_POSTURE_USER_TEXT is.

Changeset. .changeset/32837-advisory-user-text.md, @objectstack/lint patch, with Clause-②: no and Metadata-protocol: none. Precedent followed: #32790 (the #32655 PR) declared Metadata-protocol: added only because @objectstack/spec gained the authorable RuntimeAuthoringIssueSchema.userMessage key, and it shipped its packages/lint half (catalog, params, merge) as patch. This PR is that lint half alone: no spec key, no accepted value, nothing a metadata author writes changes, so none and patch.

Not in this PR. The save door composing userMessage (#32656) and the console rendering it (#32657). Until #32656 lands, every save and publish response is byte-identical.

Tests

Counts from the tree at 6f88ae2d (main 2c98485d). The head 715ce9e3 merges main e997113c through scripts/pm/os-regen-merge.sh (3 incoming commits: a hook description in packages/spec, a skills reference, PM docs; none touches packages/lint; no conflict; no generated artifact left to regenerate). After the merge: pnpm --filter @objectstack/spec build then check:generated (all 14 artifacts up to date), and the two user-text pin files, 52 passed (52), VERDICT command-exit 0.

  • packages/lint/src/finding-user-text.dashboards.test.ts (new, 24 tests):
    • exact coverage: the widget catalog holds exactly the 7 ids and the chart catalog exactly the 2, each in exactly the 11 platform locales; both are the entries FINDING_USER_TEXT_CATALOG serves; the 9 ids are pinned by value;
    • the two ids the door never returns have no catalog entry;
    • every push site rendered from the rule's real findings (12 cases: 8 widget push sites with both widget-measures-missing arms and all three chart-field-unknown positions, and both chart ids): severity warning, the exact params, every locale truthy, no undefined or template residue, every interpolated name present, and no English stand-in in any non-English locale;
    • the three chart-field-unknown arms render apart in every locale, and the two widget-measures-missing arms differ in every locale;
    • zh-Hans and en spot checks; chart-axis-not-selected names the plotted measure;
    • no params where the finding is not door advice: a query-position chart-measure-unknown error, a page chart's two presentation warnings, and measure-aggregate-incoherent;
    • from the runtime gate to the wire field: a dashboard write's chart-dimensions-missing and a report write's chart-axis-not-selected come out of runRuntimeAuthoringRules with their params, and the rendered userMessage (zh-CN request; fr-FR request in a zh-CN workspace) parses under RuntimeAuthoringIssueSchema beside the unchanged rule id and message.
  • pnpm --filter @objectstack/lint test: Test Files 203 passed (203), Tests 8639 passed (8639), VERDICT command-exit 0.
  • pnpm --filter @objectstack/lint typecheck (tsc --noEmit and check:test-typecheck): exit 0.
  • Consumer reading (@objectstack/metadata-protocol, which runs the gate on every save): Test Files 337 passed, 7 skipped (344); Tests 22799 passed, 36 skipped; VERDICT command-exit 0.
Ablations (committed first at 6f88ae2, mutated through scripts/ablation-replace.mjs, restored to the HEAD blob)
# Mutation Observed
1 validate-widget-bindings.ts: drop userTextParams at the table-count-only push site 1 failed, 23 passed (that site's render case)
2 validate-chart-bindings.ts: drop report: reportName from the report chart binding 4 failed, 20 passed (both chart render cases, the plotted-measure case, the report-write gate case)

Each mutation landed (anchor 1 → 0, blob changed) and each restore read blob == HEAD and git diff HEAD is empty.

Acceptance notes

Verification

Local subset at 6f88ae2d (the merge brought in no file this derivation reads, and the change set against main is the same 7 paths), derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (60 families), every line run with stdin closed and its exit code captured before any pipe, then reconciled with --ran: 60 derived, 60 run, 0 NOT-MEASURED (a derived zero: all 60 recorded an exit code, none is 3). All 60 exit 0. The record is spec-seat-2/r2026-11-13/out/32837-gates-ran-6f88ae2d.list in the project files.

Four families needed a prerequisite before their reading
  • node scripts/check-plugin-teardown-shape.mjs --self-test: exit 3 on the shallow clone (pinned fixture commit 621a4876 absent); exit 0 after fetching that commit.
  • pnpm check:dts-closure: exit 1 (a consumer closure built without declarations); exit 0 after a full workspace build with declarations.
  • pnpm check:dual-build-cjs-loads, pnpm check:lean-entry-closure: exit 3 PREREQUISITE NOT MET (no dist); exit 0 after the same full build.

node scripts/check-cli-command-ids.mjs (run after editing the catalogs, since a pt-BR or es sentence opening with "os " trips it): exit 0, 1322 command-id literals resolve.

CI runs the rest of the farm on this PR; its check-runs are the reading for every family outside the local subset.


Generated by Claude Code

…ntence

The widget-binding and chart-binding rules' advisory ids that the publish
door returns gain a sibling user-text catalog (all 11 platform locales),
userTextParams at each push site, and a merge into
FINDING_USER_TEXT_CATALOG. Rule ids, message and hint are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibyUPga1xgca5r6vaew
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint, touching 9 documentable anchor(s).

⛔ 2 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via validateWidgetBindings (symbol, a top-level function))
  • content/docs/releases/v17/17-1.mdx (via validateWidgetBindings (symbol, a top-level function))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 65 of 247 client-bound route-ledger rows — the other 182 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 182: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 59 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 123 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json e997113cb058b6eb733179612fff608828e282a6 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from e9c7975a4c92af846c50f578a922c4395f05e3f3 — the merge of head 715ce9e360f7706a34aa8bac1c8b0f3897f68ad0 into base e997113cb058b6eb733179612fff608828e282a6, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e9c7975a4c92af846c50f578a922c4395f05e3f3 && git checkout e9c7975a4c92af846c50f578a922c4395f05e3f3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e997113cb058b6eb733179612fff608828e282a6 715ce9e360f7706a34aa8bac1c8b0f3897f68ad0 && git checkout -B drift-repro e997113cb058b6eb733179612fff608828e282a6 && git merge --no-ff 715ce9e360f7706a34aa8bac1c8b0f3897f68ad0

node scripts/docs-audit/affected-docs.mjs --json e997113cb058b6eb733179612fff608828e282a6

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs e997113cb058b6eb733179612fff608828e282a6 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#2 · os-tesla · session_01L9qibvfX5bawZKtfa6u7j9

维护者速读

  • 改了什么:仪表盘、图表类的 9 条 lint 提示,在运行时保存时会带上用户可读的一句话(11 种平台语言),按请求语言显示;规则 id、message、hint 和 os validate/os lint 输出都不变。
  • 为什么改:非英语 Studio 里这些提示原来只显示英文;安全类提示已按 spec: user-facing refusal and advisory text is in the request locale (userMessage locale rule, advisory user text field), per ruling C on #32440 #32655 的方式本地化。
  • 风险与回滚:只加文案和参数,@objectstack/lint patch,Clause-②: no;回滚即 revert。
  • 先看:packages/lint/src/validate-widget-bindings.user-text.ts(7 条句子)和 finding-user-text.ts 的合并列表。
  • 两分钟验证:pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/finding-user-text.dashboards.test.ts,预期全绿。
  • 需要你做的:无,席位落地。非英语句子由 agent 写,已在验收说明里列出,等母语复核。

席位意见:可以落地。

席位核对

ACCEPT · seat domain:spec#2 · head 715ce9e3 · 2026-11-13T15:39Z

  1. Shape: Fixes #32837, draft, base main, 7 files, +1043/−1; changeset .changeset/32837-advisory-user-text.md (@objectstack/lint patch). Clause-②: no, Metadata-protocol: none (precedent feat(spec, lint): user-facing refusal and advisory text is in the request locale; authoring findings carry a localized user sentence, security posture first #32790's lint half), matching claim 6855540022 and dev report 6856977259.
  2. Premise: spec: user-facing refusal and advisory text is in the request locale (userMessage locale rule, advisory user text field), per ruling C on #32440 #32655 closed with the *.user-text.ts + mergeUserTextCatalogs pattern. The dev re-measured through runRuntimeAuthoringRules: 9 of the card's 11 ids reach the publish door. The seat agreed in-thread to catalog only those 9; the 2 unreachable ids (measure-aggregate-incoherent, page/visualization-without-binding) are named in Acceptance notes, under parent lint: every save-door advisory rule carries a localized user sentence (67 rule ids in 36 rule files remain after the security posture), per ruling C on #32440 #32835's Done-when alternative.
  3. Review: dispatch-gates --tier: no path-derived mandate (packages/lint only, no narrowing face), so this is the seat's own review of record. It read the code diff in full: two catalog imports and the merge list; userTextParams at the 9 push sites; on chart bindings only at position === 'report-series', with report carried on the report chart binding alone. It spot-checked chart-axis-not-selected in 8 locales for ${p.plotted} / ${p.dataset} interpolation. The pins assert exact coverage over ids × 11 locales, every push site rendered in every locale, and a runtime-gate userMessage.
  4. Gates / check-runs: dev: lint 203 files / 8639 tests, metadata-protocol consumer 22799 passed, 60/60 derived gates exit 0, 2 ablations red as expected. CI on 715ce9e3: 66 runs, 55 success, 11 skipped, 0 failed. K = 1, no new locale pack.
  5. Accepted deviations and out-of-scope findings: the 2 unreachable ids above stay on the English message. Agent-written non-English sentences are listed for the native-review round. Sibling lint: the automation writes: approvals, flows, hooks, actions and email templates advisories carry a localized user sentence (27 rule ids in 11 rule files), per ruling C on #32440 #32836 (PR fix(lint): the approval and flow advisories a flow save returns carry a user sentence in every platform locale #33120) adds lines to the same FINDING_USER_TEXT_CATALOG list; whichever lands second merges main once.
  6. Landing: not governed (check-governed-merges --pr 33118), 1044 changed lines. The seat readies the PR and arms auto-merge under the maintainer's standing words 「车道经理应该使用 pm-dispatch 技能审核和落地pr」. On MERGED: lint: the dashboards, charts and widgets advisories carry a localized user sentence (11 rule ids in 3 rule files), per ruling C on #32440 #32837 closes via Fixes; pm:dispatched comes off.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 13, 2026 15:39
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 13, 2026
Merged via the queue into main with commit 5c005e0 Nov 13, 2026
67 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-4p4z2c branch November 13, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lint: the dashboards, charts and widgets advisories carry a localized user sentence (11 rule ids in 3 rule files), per ruling C on #32440

2 participants